package com.atguigu.yygh.order.service.impl;

import com.atguigu.exphandler.YyghException;
import com.atguigu.yygh.enums.RefundStatusEnum;
import com.atguigu.yygh.model.order.OrderInfo;
import com.atguigu.yygh.model.order.PaymentInfo;
import com.atguigu.yygh.model.order.RefundInfo;
import com.atguigu.yygh.order.mapper.OrderInfoMapper;
import com.atguigu.yygh.order.mapper.PaymentInfoMapper;
import com.atguigu.yygh.order.mapper.RefundInfoMapper;
import com.atguigu.yygh.order.service.PaymentInfoService;
import com.atguigu.yygh.order.service.WeixinService;
import com.atguigu.yygh.order.util.ConstantPropertiesUtils;
import com.atguigu.yygh.order.util.HttpClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.wxpay.sdk.WXPayUtil;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class WeixinServiceImpl implements WeixinService {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    OrderInfoMapper orderInfoMapper;

    @Autowired
    PaymentInfoMapper paymentInfoMapper;

    @Autowired
    PaymentInfoService paymentInfoService;

    @Autowired
    RefundInfoMapper refundInfoMapper;

    @Override
    public Map createNative(Long orderId) {

        try {
            //1、从redis中检查该订单对应的codeUrl是否存在
            Map map = (Map)redisTemplate.boundValueOps(orderId).get();
            if(map!=null){
                return map;
            }


            //根据订单id查询订单对象
            OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
            if(orderInfo==null){
                throw new YyghException(20001,"订单不存在");
            }

            //为当前订单，点击支付记录
            paymentInfoService.createPaymentInfo(orderInfo);


            //2、redis中没有该订单的支付链接，调用微信支付端的“统一下单” 接口
            String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";


            Map<String, String> paramMap = new HashMap<>();//不需要sign参数了
            paramMap.put("appid", ConstantPropertiesUtils.APPID);
            paramMap.put("mch_id",ConstantPropertiesUtils.PARTNER);
            paramMap.put("nonce_str",WXPayUtil.generateNonceStr());

            String reserveDateString = new DateTime(orderInfo.getReserveDate()).toString("yyyy/MM/dd");
            String body = reserveDateString + "就诊"+ orderInfo.getHosname() +"|"+ orderInfo.getDepname();

            paramMap.put("body",body);//日期 + 医院名称+科室名称

            paramMap.put("out_trade_no",orderInfo.getOutTradeNo());//订单的outTradeNo（订单编号）



            paramMap.put("total_fee","1");//测试金额1分

            paramMap.put("spbill_create_ip","127.0.0.1");
            paramMap.put("notify_url","http://guli.shop/api/order/weixinPay/weixinNotify");//用于异步接收支付结果状态的接口

            paramMap.put("trade_type","NATIVE");


            //带有sign属性的xml字符串
            String xmlString = WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY);

            //使用工具类接口调用
            HttpClient httpClient = new HttpClient(url);
            httpClient.setHttps(true);//接口https协议
            httpClient.setXmlParam(xmlString);//设置参数
            httpClient.post();//发起post类型请求

            //微信端的返回值（xml字符串）
            String content = httpClient.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(content);

            String code_url = resultMap.get("code_url");
            if(StringUtils.isEmpty(code_url)){//已经支付成功了，再获取codeUrl，为null
                throw new YyghException(20001,"微信端统一下单接口调用失败");
            }


            map = new HashMap();
            map.put("codeUrl",code_url);
            //添加到redis中,暂存五分钟
            redisTemplate.boundValueOps(orderId).set(map,5, TimeUnit.MINUTES);

            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public Map queryStatus(Long orderId) {

        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);

        String url = "https://api.mch.weixin.qq.com/pay/orderquery";

        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("appid",ConstantPropertiesUtils.APPID);
        paramMap.put("mch_id",ConstantPropertiesUtils.PARTNER);
        paramMap.put("out_trade_no",orderInfo.getOutTradeNo());//要和第一步调用“统一下单”接口时使用的outTradeNo一致
        paramMap.put("nonce_str",WXPayUtil.generateNonceStr());

        try {
            String xmlParam = WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY);

            HttpClient httpClient = new HttpClient(url);
            httpClient.setHttps(true);
            httpClient.setXmlParam(xmlParam);
            httpClient.post();



            //微信端的返回值
            Map<String, String> result = WXPayUtil.xmlToMap(httpClient.getContent());

            return result;


        } catch (Exception e) {
            e.printStackTrace();
        }


        return null;
    }

    @Override
    public void refund(Long orderId) {

        //判断该订单的退款记录是否存在（根据order_id 查询退款记录）
        QueryWrapper<RefundInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id",orderId);
        RefundInfo refundInfo = refundInfoMapper.selectOne(queryWrapper);

        //支付记录必须要查询，创建退款记录时需要使用支付记录中的数据
        PaymentInfo paymentInfo = paymentInfoService.getPayment(orderId);

        //退款记录不存在，创建默认的退款记录
        if (refundInfo == null){

            //利用支付记录中的数据，创建一个退款记录
            refundInfo = new RefundInfo();

            //订单、支付记录 、退款记录
            refundInfo.setOutTradeNo(paymentInfo.getOutTradeNo());
            refundInfo.setOrderId(paymentInfo.getOrderId());
            //支付方式(支付记录中找)
            refundInfo.setPaymentType(paymentInfo.getPaymentType());

            refundInfo.setTotalAmount(paymentInfo.getTotalAmount());//支付金额
            refundInfo.setSubject(paymentInfo.getSubject());
            refundInfo.setRefundStatus(RefundStatusEnum.UNREFUND.getStatus());//退款记录的状态(退款中=1)

            refundInfoMapper.insert(refundInfo);
        }

        //判断退款记录的退款状态，如果为已退款，不需要调用微信端的退款接口
        if (refundInfo.getRefundStatus()==RefundStatusEnum.REFUND.getStatus()){
            //已退款，不需要调用微信端的退款接口
            return;
        }

        //执行退款流程，调用微信端的退款接口
        String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";

        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("appid",ConstantPropertiesUtils.APPID);
        paramMap.put("mch_id",ConstantPropertiesUtils.PARTNER);
        paramMap.put("nonce_str",WXPayUtil.generateNonceStr());
        paramMap.put("out_trade_no",paymentInfo.getOutTradeNo());//订单的编号（和支付记录的是一致）

        paramMap.put("out_refund_no", "tk_"+ paymentInfo.getOutTradeNo());//退款单号(保证系统唯一即可) 随机字符串即可

        paramMap.put("total_fee","1");//订单支付的金额
        paramMap.put("refund_fee","1");//退款金额

        try {
            //退款接口的地址
            String xml = WXPayUtil.generateSignedXml(paramMap, ConstantPropertiesUtils.PARTNERKEY);

            HttpClient httpClient = new HttpClient(url);
            httpClient.setHttps(true);//协议
            httpClient.setXmlParam(xml);//参数（xml格式的字符串）

            //退款时需要两个方法
            httpClient.setCert(true);//true需要证书
            httpClient.setCertPassword(ConstantPropertiesUtils.PARTNER);//商户号

            httpClient.post();//发起post类型的请求

            //返回值！
            //微信端返回的xml字符串
            String content = httpClient.getContent();
            //xml格式的字符串转成map对象
            Map<String, String> result = WXPayUtil.xmlToMap(content);

            //map中的两个字段如果都为SUCCESS，表示微信端成功的接收到了我们的退款申请，如果希望得到退款是否成功，需要调用查询退款接口
            String return_code = result.get("return_code");
            String result_code = result.get("result_code");

            //并不能保证退款一定是成功的（如果是FAIL，说明接口调用失败）
            //这样说明退款成功了，不够严谨（需要调用查询退款接口）
            if ("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)){
                //退款成功，完善退款记录
                refundInfo.setRefundStatus(RefundStatusEnum.REFUND.getStatus());//已退款
                refundInfo.setCallbackTime(new Date());
                refundInfo.setCallbackContent(result.toString());
                refundInfo.setTradeNo(result.get("refund_id"));//微信端的退款单号
                refundInfoMapper.updateById(refundInfo);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }














}
